/*
 * Copyright 2018-2019 The Apache Software Foundation
 * Modifications 2019 Orient Securities Co., Ltd.
 * Modifications 2019 BoCloud Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.orientsec.grpc.registry.support;

import com.orientsec.grpc.registry.Registry;
import com.orientsec.grpc.registry.RegistryFactory;
import com.orientsec.grpc.registry.RegistryService;
import com.orientsec.grpc.registry.common.Constants;
import com.orientsec.grpc.registry.common.URL;
import com.orientsec.grpc.registry.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;



/**
 * Created by heiden on 2017/3/15.
 *  @since  modify by wjw 2017/4/14 change Logger from  org.slf4j.Logger to java.util.logging.Logger
 */
public abstract class AbstractRegistryFactory implements RegistryFactory {

  // 日志输出
  private static final Logger logger = LoggerFactory.getLogger(AbstractRegistryFactory.class);

  // 注册中心获取过程锁
  private static final ReentrantLock LOCK = new ReentrantLock();

  // 注册中心集合 Map<RegistryAddress, Registry>
  private static final Map<String, Registry> REGISTRIES = new ConcurrentHashMap<String, Registry>();

  /**
   * 获取所有注册中心
   *
   * @return 所有注册中心
   */
  public static Collection<Registry> getRegistries() {
    return Collections.unmodifiableCollection(REGISTRIES.values());
  }

  /**
   * 关闭所有已创建注册中心
   */
  public static void destroyAll() {
    logger.debug("Close all registries " + getRegistries());
    // 锁定注册中心关闭过程
    LOCK.lock();
    try {
      for (Registry registry : getRegistries()) {
        try {
          registry.destroy();
        } catch (Throwable e) {
          logger.error(e.getMessage(), e);
        }
      }
      REGISTRIES.clear();
    } finally {
      // 释放锁
      LOCK.unlock();
    }
  }

  public Registry getRegistry(URL url) {
    String key = getRegistryKey(url);
    // 锁定注册中心获取过程，保证注册中心单一实例
    LOCK.lock();
    try {
      Registry registry = REGISTRIES.get(key);
      if (registry != null) {
        return registry;
      }
      registry = createRegistry(url);
      if (registry == null) {
        throw new IllegalStateException("Can not create registry " + url);
      }
      REGISTRIES.put(key, registry);
      return registry;
    } finally {
      // 释放锁
      LOCK.unlock();
    }
  }

  private String getRegistryKey(URL url){
    url = url.setPath(RegistryService.class.getName())
            .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
            .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
    String key = url.toServiceString();
    String id = url.getId();
    if (StringUtils.isNotEmpty(id)) {
      key = key + "-" + id;
    }
    return key;
  }

  @Override
  public void releaseRegistry(URL url) {
    String key = getRegistryKey(url);
    // 锁定注册中心获取过程，保证注册中心单一实例
    LOCK.lock();
    try {
      Registry registry = REGISTRIES.get(key);
      if (registry != null) {
        registry.destroy();
        REGISTRIES.remove(key);
      }
    } finally {
      // 释放锁
      LOCK.unlock();
    }
  }

  protected abstract Registry createRegistry(URL url);

}
